package cn.damai.mine.thread.countDownLatch;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CountDownLatchTest {
	
	/**
	 * public void countDown()
			递减锁存器的计数，如果计数到达零，则释放所有等待的线程。如果当前计数大于零，则将计数减少。如果新的计数为零，出于线程调度目的，将重新启用所有的等待线程。
			如果当前计数等于零，则不发生任何操作。
	 * await 使当前线程在锁存器倒计数至零之前一直等待，除非线程被中断或超出了指定的等待时间。
	 * 任务分两类：一类是实现了Runnable接口的类，一类是实现了Callable接口的类。两者都可以被ExecutorService执行，
	 * 当将一个Callable的对象传递给ExecutorService的submit方法，则该call方法自动在一个线程上执行，并且会返回执行结果Future对象。
	 * 同样，将Runnable的对象传递给ExecutorService的submit方法，则该run方法自动在一个线程上执行，并且会返回执行结果Future对象，
	 * 但是在该Future对象上调用get方法，将返回null。
	 * 我们创建一个初始计数为1的CountDownLatch，并让所有线程都在这个锁上等待，我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行
	 * 
	 */

	// 模拟了100米赛跑，10名选手已经准备就绪，只等裁判一声令下。当所有人都到达终点时，比赛结束。
	public static void main(String[] args) throws InterruptedException {

		// 开始的倒数锁
		final CountDownLatch begin = new CountDownLatch(1);

		// 结束的倒数锁
		final CountDownLatch end = new CountDownLatch(10);

		// 十名选手
		final ExecutorService exec = Executors.newFixedThreadPool(10);

		List<Future<Boolean>> list = new ArrayList<Future<Boolean>>();
		
		/*for (int index = 0; index < 10; index++) {
			final int NO = index + 1;
			Runnable run = new Runnable() {
				public void run() {
					try {
						// 如果当前计数为零，则此方法立即返回。
						// 等待
						begin.await();
						Thread.sleep((long) (Math.random() * 10000));
						System.out.println("No." + NO + " arrived");
					} catch (InterruptedException e) {
					} finally {
						// 每个选手到达终点时，end就减一
						end.countDown();
					}
				}
			};
			Future fu = exec.submit(run);
			list.add(fu);
		}*/
		
		for (int index = 0; index < 10; index++) {
			final int NO = index + 1;
			
			Callable call = new Callable() {
				@Override
				public Boolean call() {
					// TODO Auto-generated method stub
					try {
						// 如果当前计数为零，则此方法立即返回。
						// 等待
						begin.await();
						Thread.sleep((long) (Math.random() * 10000));
						System.out.println("No." + NO + " arrived");
					} catch (InterruptedException e) {
					} finally {
						// 每个选手到达终点时，end就减一
						end.countDown();
					}
					return true;
				}
			};
			Future fu = exec.submit(call);
			list.add(fu);
		}
		
		System.out.println("Game Start");
		// begin减一，开始游戏
		begin.countDown();
		// 等待end变为0，即所有选手到达终点
		end.await();
		System.out.println("Game Over");
		exec.shutdown();
		
		for (Future future : list) {
			try {
				System.out.println("hah:"+future.get());
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
		
	}

}
